package gs

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"fmt"
	"log"
	"math/rand"
	"regexp"
	"strings"
	"time"
)

var (
	RAND = rand.New(rand.NewSource(time.Now().Unix()))
)

func (str Str) RandStr(l int) Str {
	buf := make([]byte, l)
	cstr := "abcdefghijklmeopqrstuvwxyz"
	c := cstr[RAND.Intn(26)]
	RAND.Read(buf)
	return Str(string(c) + hex.EncodeToString(buf))
}

func (str Str) Format(mapKeys Dict[string]) Str {
	if !str.In("$${") {
		return str
	} else {
		e := str
		keys := Strs{}.FromMapKeys(mapKeys)
		// fmt.Println(keys)
		keys = keys.Sort(func(k1, k2 Str) bool {
			return len(mapKeys[k1.String()]) > len(mapKeys[k2.String()])
		})
		// fmt.Println("e:", e)
		for _, key := range keys.List() {
			// fmt.Println("$${" + key + "}")
			v := mapKeys[key]
			if e.In(key) {

				e = e.Replace("$${"+key+"}", v)
				// fmt.Println("End", e)
			}
		}
		// fmt.Println("End", e)
		return e
	}
}

func (str Str) FormatDict(mapKeys Dict[Str]) Str {
	return str.Format(mapKeys.MapString())
}

func (str Str) QuoteMark() (newStr Str, quotedmapKey Dict[Str]) {
	quotedmapKey = make(Dict[Str])
	newStr = str
	str.QuotedStrs().Sort(func(k1, k2 Str) bool {
		return k2.Len() < k1.Len()
	}).Every(func(ix int, key Str) {
		keyrand := key.RandStr(8)
		// fmt.Println(key.String(), newStr.In(key.String()))
		newStr = newStr.Replace(key.String(), fmt.Sprintf("$${%s}", keyrand))
		// keys, _ := strconv.Unquote(key.String())
		// mapKey[keyrand.String()] = Str(keys)
		quotedmapKey[keyrand.String()] = key
	})
	return
}

func (str Str) ExtractReMark(pre string, end string) (newStr Str, quotedMapKey Dict[Str]) {
	quotedMapKey = make(Dict[Str])
	newStr = str
	str.ExtractByRE(pre, end).Sort(func(k1, k2 Str) bool {
		return k2.Len() < k1.Len()
	}).Every(func(ix int, key Str) {
		keyrand := key.RandStr(8)
		// fmt.Println(key.String(), newStr.In(key.String()))
		newStr = newStr.Replace(key.String(), fmt.Sprintf("$${%s}", keyrand))
		// keys, _ := strconv.Unquote(key.String())
		// quotedMapKey[keyrand.String()] = Str(keys)
		quotedMapKey[keyrand.String()] = key
	})
	return
}

func (str Str) ReMarkColor(pre, end string) Str {
	s, k := str.ExtractReMark(pre, end)
	return s.FormatDict(k.With(func(k string, v Str) Str {
		return v.Color("B", "U", "F", "g")
	}))
}

func (str Str) MarkColor(pre, end string) Str {
	s, k := str.ExtractMark(pre, end)
	return s.FormatDict(k.With(func(k string, v Str) Str {
		return v.Color("B", "U", "F", "g")
	}))
}

func (str Str) ExtractMark(pre string, end string) (newStr Str, mapKey Dict[Str]) {
	mapKey = make(Dict[Str])
	newStr = str
	str.Extract(pre, end).Sort(func(k1, k2 Str) bool {
		return k2.Len() < k1.Len()
	}).Every(func(ix int, key Str) {
		keyrand := key.RandStr(8)
		// fmt.Println(key.String(), newStr.In(key.String()))
		newStr = newStr.Replace(key.String(), fmt.Sprintf("$${%s}", keyrand))
		// keys, _ := strconv.Unquote(key.String())
		// mapKey[keyrand.String()] = Str(keys)
		mapKey[keyrand.String()] = key
	})
	return
}

func (str Str) QuoteMarkMap() (newStr Str, mapKey map[string]string) {
	mapKey = make(map[string]string)
	newStr = str
	str.QuotedStrs().Sort(func(k1, k2 Str) bool {
		return k2.Len() < k1.Len()
	}).Every(func(ix int, key Str) {
		keyrand := key.RandStr(8)
		// fmt.Println(key.String(), newStr.In(key.String()))
		newStr = newStr.Replace(key.String(), fmt.Sprintf("$${%s}", keyrand))
		// mapKey[string(keyrand)] = key.String()

		mapKey[keyrand.String()] = key.String()
	})
	return
}

func (str Str) QuotedStrsDebug() (strs Strs) {
	tmpStr := str
	goon := true

	// fmt.Println("hhh")
	last := ""
	// keys := Dict[Str]{}
	str.Find(`('.+?')`).Every(func(no int, i Str) {
		if i == `'"'` {
			tmpStr = tmpStr.Replace(`'"'`, "[PAD]")
		}
	})
	for goon {
		buffer := strings.NewReader(tmpStr.String())
		es := bufio.NewScanner(buffer)
		buf := make([]byte, 1)
		es.Buffer(buf, 100*1024*1024)
		offset := 0
		es.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
			if !atEOF {
				// Str(data).Color("B", "g").Println(74)
				// time.Sleep(1 * time.Second)
				if bytes.HasPrefix(data, []byte("`")) {
					if i := bytes.Index(data[1:], []byte("`")); i >= 0 {
						offset += i + 2
						return i + 2, data[:i+2], nil
					}
					// fmt.Printf("[s] more data:%d\r", len(data))
					return 0, nil, nil
				} else if bytes.HasPrefix(data, []byte("\"")) {
					// Str(data).Color("m").Println("pre")
					// time.Sleep(3 * time.Second)
					if i := bytes.Index(data[1:], []byte("\"")); i >= 0 {
						if i3 := bytes.LastIndex(data[1:], []byte("\"")); i3 > 0 {
							if i3-1 > -1 && data[i3] == '\\' {
								// 这个分支存在 转义 但没有结束符,more data
								// Str(data[:i3]).Println("85")
								if i3-2 > -1 && data[i3-1] == '\\' {

								} else {
									return 0, nil, nil
								}
							}
						}
						if i > -1 && data[i] == '\\' {
							// Str(data[:i+2]).Println("94")

							if i-1 > -1 && data[i-1] == '\\' {
								offset += i + 2
								return i + 2, data[:i+2], nil
							} else {
								for {
									if i2 := bytes.Index(data[i+1:], []byte("\"")); i2 >= 0 {
										if i2 > -1 && data[i+i2] == '\\' {
											if i2-1 > -1 && data[i+i2-1] == '\\' {

											} else {
												i += i2 + 1
												continue
											}
										}
										offset += i2 + i + 2

										// Str(data[:i+i2+2]).Println("104")
										return i2 + i + 2, data[:i+i2+2], nil
									}
								}
							}
						} else {
							offset += i + 2
							// Str(data[:i+2]).Println("111")
							return i + 2, data[:i+2], nil

						}
					}
					// fmt.Printf("[`] more data:%d\r", len(data))
					return 0, nil, nil
				} else {
					i := bytes.Index(data, []byte("`"))
					i2 := bytes.Index(data, []byte("\""))
					if i2 > -1 && i > -1 {
						if i2 < i {
							if i2-1 > -1 && data[i2-1] == '\\' {

								if i2-2 > -1 && data[i2-2] == '\\' {
									// \\ is not slash
								} else {
									i2 += 1
								}
							}

							offset += i2
							return i2, nil, nil

						} else {
							if i-1 > -1 && data[i-1] == '\\' {

								if i-2 > -1 && data[i-2] == '\\' {
									// \\ is not slash
								} else {
									i += 1
								}
							}

							offset += i
							return i, nil, nil
						}
					} else if i2 > -1 {
						if i2-1 > -1 && data[i2-1] == '\\' {
							if i2-2 > -1 && data[i2-2] == '\\' {
								// \\ is not slash
							} else {
								i2 += 1
							}
						}

						offset += i2
						return i2, nil, nil
					} else if i > -1 {
						if i-1 > -1 && data[i-1] == '\\' {
							if i-2 > -1 && data[i-2] == '\\' {
								// \\ is not slash
							} else {
								i += 1
							}

						}

						offset += i
						return i, nil, nil
					} else {
						// fmt.Printf("[n] more data:%d\r", len(data))
						// time.Sleep(1 * time.Second)
						return 0, nil, nil
					}
				}
			} else {
				// fmt.Println("[ss2]:", string(data))
				// time.Sleep(2 * time.Second)
				i := bytes.Index(data, []byte("`"))
				i2 := bytes.Index(data, []byte("\""))

				if i2 == 0 {
					if i2e := bytes.Index(data[1:], []byte("\"")); i2e > -1 {
						offset += i2e + 2
						return i2e + 2, data[:i2e+2], nil
					}

				} else if i == 0 {
					if ie := bytes.Index(data[1:], []byte("`")); ie > -1 {
						offset += ie + 2
						return 2, data[:ie+2], nil
					}
				}

				fmt.Println("i2,", i2, "i,", i)
				if Str(data).Str() == last {
					log.Fatal(Str(data))
				} else {
					last = Str(data).Str()
				}
				Str(data).Color("r").Println(offset)

				if i2 > -1 && i > -1 {

					if i2 < i {

						offset += i2 + 1
					} else {
						offset += i + 1
					}
				} else if i2 > -1 {
					offset += i2 + 1
				} else if i > -1 {
					offset += i + 1
				} else {
					goon = false

				}
				// tmpStr.Println()
				tmpStr[offset:].Color("g", "B").Println(offset, i, i2)

				return 0, nil, nil

			}
		})

		for es.Scan() {
			ee := Str(es.Text())
			ee.Color("b", "g").Println("ext Str")
			strs = strs.Add(ee)
		}
		if goon {
			tmpStr = tmpStr[offset:]
		}
		// fmt.Println("[ss]:", tmpStr)
		// time.Sleep(1 * time.Second)

	}
	return
}

func (str Str) QuotedStrs() (strs Strs) {
	tmpStr := str
	goon := true

	// fmt.Println("hhh")
	// last := ""
	// keys := Dict[Str]{}
	str.Find(`('.+?')`).Every(func(no int, i Str) {
		if i == `'"'` {
			tmpStr = tmpStr.Replace(`'"'`, "[PAD]")
		}
	})
	for goon {
		buffer := strings.NewReader(tmpStr.String())
		es := bufio.NewScanner(buffer)
		buf := make([]byte, 1)
		es.Buffer(buf, 100*1024*1024)
		offset := 0
		es.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
			if !atEOF {
				// Str(data).Color("B", "g").Println(74)
				// time.Sleep(1 * time.Second)
				if bytes.HasPrefix(data, []byte("`")) {
					if i := bytes.Index(data[1:], []byte("`")); i >= 0 {
						offset += i + 2
						return i + 2, data[:i+2], nil
					}
					// fmt.Printf("[s] more data:%d\r", len(data))
					return 0, nil, nil
				} else if bytes.HasPrefix(data, []byte("\"")) {
					// Str(data).Color("m").Println("pre")
					// time.Sleep(3 * time.Second)
					if i := bytes.Index(data[1:], []byte("\"")); i >= 0 {
						if i3 := bytes.LastIndex(data[1:], []byte("\"")); i3 > 0 {
							if i3-1 > -1 && data[i3] == '\\' {
								// 这个分支存在 转义 但没有结束符,more data
								// Str(data[:i3]).Println("85")
								if i3-2 > -1 && data[i3-1] == '\\' {

								} else {
									return 0, nil, nil
								}
							}
						}
						if i > -1 && data[i] == '\\' {
							// Str(data[:i+2]).Println("94")

							if i-1 > -1 && data[i-1] == '\\' {
								offset += i + 2
								return i + 2, data[:i+2], nil
							} else {
								for {
									if i2 := bytes.Index(data[i+1:], []byte("\"")); i2 >= 0 {
										if i2 > -1 && data[i+i2] == '\\' {
											if i2-1 > -1 && data[i+i2-1] == '\\' {

											} else {
												i += i2 + 1
												continue
											}
										}
										offset += i2 + i + 2

										// Str(data[:i+i2+2]).Println("104")
										return i2 + i + 2, data[:i+i2+2], nil
									}
								}
							}
						} else {
							offset += i + 2
							// Str(data[:i+2]).Println("111")
							return i + 2, data[:i+2], nil

						}
					}
					// fmt.Printf("[`] more data:%d\r", len(data))
					return 0, nil, nil
				} else {
					i := bytes.Index(data, []byte("`"))
					i2 := bytes.Index(data, []byte("\""))
					if i2 > -1 && i > -1 {
						if i2 < i {
							if i2-1 > -1 && data[i2-1] == '\\' {

								if i2-2 > -1 && data[i2-2] == '\\' {
									// \\ is not slash
								} else {
									i2 += 1
								}
							}

							offset += i2
							return i2, nil, nil

						} else {
							if i-1 > -1 && data[i-1] == '\\' {

								if i-2 > -1 && data[i-2] == '\\' {
									// \\ is not slash
								} else {
									i += 1
								}
							}

							offset += i
							return i, nil, nil
						}
					} else if i2 > -1 {
						if i2-1 > -1 && data[i2-1] == '\\' {
							if i2-2 > -1 && data[i2-2] == '\\' {
								// \\ is not slash
							} else {
								i2 += 1
							}
						}

						offset += i2
						return i2, nil, nil
					} else if i > -1 {
						if i-1 > -1 && data[i-1] == '\\' {
							if i-2 > -1 && data[i-2] == '\\' {
								// \\ is not slash
							} else {
								i += 1
							}

						}

						offset += i
						return i, nil, nil
					} else {
						// fmt.Printf("[n] more data:%d\r", len(data))
						// time.Sleep(1 * time.Second)
						return 0, nil, nil
					}
				}
			} else {
				// fmt.Println("[ss2]:", string(data))
				// time.Sleep(2 * time.Second)
				i := bytes.Index(data, []byte("`"))
				i2 := bytes.Index(data, []byte("\""))

				if i2 == 0 {
					if i2e := bytes.Index(data[1:], []byte("\"")); i2e > -1 {
						offset += i2e + 2
						return i2e + 2, data[:i2e+2], nil
					}

				} else if i == 0 {
					if ie := bytes.Index(data[1:], []byte("`")); ie > -1 {
						offset += ie + 2
						return ie + 2, data[:ie+2], nil
					}
				}

				// fmt.Println("i2:", i2, " i:", i)
				// if Str(data).Str() == last {
				// 	log.Fatal(Str(data))
				// } else {
				// 	last = Str(data).Str()
				// }
				// Str(data).Color("r").Println(offset)

				if i2 > -1 && i > -1 {

					if i2 < i {

						offset += i2
					} else {
						offset += i
					}
				} else if i2 > -1 {
					offset += i2
				} else if i > -1 {
					offset += i
				} else {
					goon = false

				}
				// tmpStr.Println()
				// tmpStr[offset:].Color("g", "B").Println(offset, i, i2)

				return 0, nil, nil

			}
		})

		for es.Scan() {
			ee := Str(es.Text())
			// ee.Color("b", "g").Println("Str")

			strs = strs.Add(ee)
		}
		if goon {
			tmpStr = tmpStr[offset:]
		}
		// fmt.Println("[ss]:", tmpStr)
		// time.Sleep(1 * time.Second)

	}
	return
}

func (str Str) lines() (strs Strs) {
	quoted := false
	lines := strings.FieldsFunc(str.Str(), func(r rune) bool {
		if r == '"' {
			quoted = !quoted
		}
		return !quoted && r == '\n'
	})
	return strs.Adds(lines...)
	// line := Str("")
	// for {
	// 	st, et := str.Index("\n")
	// 	if st < 0 {
	// 		if str != "" {
	// 			strs = strs.Add(str)
	// 		}
	// 		break
	// 	} else {
	// 		if st > 0 {
	// 			if str[st-1] != '\\' {
	// 				strs = strs.Add(line + str[:et])
	// 				str = str[et:]
	// 				line = Str("")
	// 			} else {
	// 				line += str[:et]
	// 				str = str[et:]
	// 			}
	// 		}
	// 	}
	// }
	// return
}

func (str Str) RemoveCommit() (nstr Str) {
	// nstr = str.lines().With(func(no int, line Str) Str {
	// 	if line.Trim().StartsWith("//") {
	// 		return ""
	// 	} else if line.In("//") {
	// 		fs := line.SplitSkiptQuote("//", 2)
	// 		return fs[0]
	// 	} else {
	// 		return line
	// 	}
	// }).Join("\n")

	nstr = str.TextEveryLineWith(func(ix int, line Str) Str {

		if line.Trim().StartsWith("//") {
			// line.Color("r").Println(ix)
			return ""
		} else if line.In("//") {
			fs := line.SplitSkiptQuote("//", 3)
			// fmt.Println(fs)
			// fs[0].Color("g").Println(ix)
			return fs[0]
		} else {
			// line.Println(ix)
			return line
		}
	})
	commit := false
	nstr = nstr.TextEveryLineWith(func(lineno int, oldLine Str) Str {
		if oldLine.Trim().StartsWith("/*") {
			commit = true
			return ""
		} else if commit && oldLine.In("*/") {
			e := oldLine.SplitSkiptQuote("*/", 2)[1]
			commit = false
			return e
		} else if commit {
			return ""
		} else {
			return oldLine
		}
	})
	// for nstr.In("/*") && nstr.In("*/") {
	// 	st, et := nstr.Index("/*")
	// 	_, eet := nstr[et:].Index("*/")
	// 	commit := nstr[st : eet+et]
	// 	nstr = nstr.Replace(commit.String(), "")
	// }
	return
}

func (str Str) EveryLineContext(nline int, deal func(pretext, nextText Str, lineno int, line Str)) {
	preLins := List[Str]{}
	nextLines := List[Str]{}
	// var lastLine Str

	str.EveryLine(func(lineno int, line Str) {
		if lineno < nline {
			nextLines = nextLines.Add(line)
		} else {
			thisno := lineno - nline
			thisline := nextLines[0]
			nextLines = nextLines.Add(line)
			nextLines = nextLines[1:]
			deal(preLins.Join("\n"), nextLines.Join("\n"), thisno, thisline)
			preLins = preLins.Add(thisline)
			// lastLine = thisline
			if preLins.Count() > nline {
				preLins = preLins[1:]
			}
		}
		// if lastLine != "" {
		// 	preLins = preLins.Add(lastLine)
		// 	preLins = preLins[1:]

		// }
	})
}

func (str Str) Extract(pre string, end ...string) (strs Strs) {
	// fmt.Println("quote be")
	raw, mapKeys := str.QuoteMark()
	// fmt.Println("quote af")
	tmpStr := raw
	goon := true
	// raw.Color("y").Println("raw")
	for goon {
		offset := 0
		buffer := strings.NewReader(tmpStr.String())

		es := bufio.NewScanner(buffer)
		buf := make([]byte, 1)
		es.Buffer(buf, 100*1024*1024)
		endPre := pre
		if end != nil {
			endPre = end[0]
		}
		// time.Sleep(5 * time.Second)
		es.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {

			if !atEOF {

				if prei := bytes.Index(data, []byte(pre)); prei >= 0 {
					if prei == 0 {

						if suffix := bytes.Index(data[1:], []byte(endPre)); suffix >= 0 {
							// Str(data[1:suffix]).Println(272)
							if subPre := bytes.Index(data[1:], []byte(pre)); subPre > 0 && subPre < suffix {
								// 最大匹配

								// 先确认能闭合
								preCount := bytes.Count(data[1:], []byte(pre))
								endCount := bytes.Count(data[1:], []byte(endPre))
								if endCount < preCount+1 {
									// 闭合符号不够 more data
									// Str(data[1:suffix]).Println(281)
									return 0, nil, nil
								} else {
									subOffset := 0
									for {
										subSuffix := bytes.Index(data[1+subOffset:], []byte(endPre))
										subPrefix := bytes.Index(data[1+subOffset:], []byte(pre))

										if subPrefix < subSuffix {
											subOffset += subSuffix + 1
										} else {
											return subOffset + subSuffix + 2, data[:subOffset+subSuffix+2], nil
										}

									}

								}
							}
							suffix += len(endPre)
							offset += suffix + 1

							return suffix + 1, data[0 : suffix+1], nil
						}

						// Str(data).Println(304)
						return 0, nil, nil
					} else {
						offset += prei
						return prei, nil, nil
					}
				}

			} else {
				if prei := bytes.Index(data, []byte(pre)); prei > 0 {
					offset += prei
				} else if prei == 0 {
					if subSuffix := bytes.Index(data[len(pre):], []byte(endPre)); subSuffix > -1 {
						subSuffix += len(pre)
						return subSuffix, data[:subSuffix], nil
					} else {
						goon = false
					}
				} else {
					goon = false
				}
			}
			return 0, nil, nil

		})
		for es.Scan() {
			text := Str(es.Text())
			text = text.Format(mapKeys.MapString())

			strs = strs.Add(Str(text))
		}
		if goon {
			tmpStr = tmpStr[offset:]
		}

	}
	return
}
func (str Str) ExtractRaw(pre string, end ...string) (strs Strs) {
	// fmt.Println("quote be")
	raw := str
	// fmt.Println("quote af")
	tmpStr := raw
	goon := true
	// raw.Color("y").Println("raw")
	for goon {
		offset := 0
		buffer := strings.NewReader(tmpStr.String())

		es := bufio.NewScanner(buffer)
		buf := make([]byte, 1)
		es.Buffer(buf, 1024*1024*1024)
		endPre := pre
		if end != nil {
			endPre = end[0]
		}
		// time.Sleep(5 * time.Second)
		es.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {

			if !atEOF {

				if prei := bytes.Index(data, []byte(pre)); prei >= 0 {
					if prei == 0 {

						if suffix := bytes.Index(data[1:], []byte(endPre)); suffix >= 0 {
							// Str(data[1:suffix]).Println(272)
							if subPre := bytes.Index(data[1:], []byte(pre)); subPre > 0 && subPre < suffix {
								// 最大匹配

								// 先确认能闭合
								preCount := bytes.Count(data[1:], []byte(pre))
								endCount := bytes.Count(data[1:], []byte(endPre))
								if endCount < preCount+1 {
									// 闭合符号不够 more data
									// Str(data[1:suffix]).Println(281)
									return 0, nil, nil
								} else {
									subOffset := 0
									for {
										subSuffix := bytes.Index(data[1+subOffset:], []byte(endPre))
										subPrefix := bytes.Index(data[1+subOffset:], []byte(pre))

										if subPrefix < subSuffix {
											subOffset += subSuffix + 1
										} else {
											return subOffset + subSuffix + 2, data[:subOffset+subSuffix+2], nil
										}

									}

								}
							}
							suffix += len(endPre)
							offset += suffix + 1

							return suffix + 1, data[0 : suffix+1], nil
						}

						// Str(data).Println(304)
						return 0, nil, nil
					} else {
						offset += prei
						return prei, nil, nil
					}
				}

			} else {
				if prei := bytes.Index(data, []byte(pre)); prei > 0 {
					offset += prei
				} else if prei == 0 {
					if subSuffix := bytes.Index(data[len(pre):], []byte(endPre)); subSuffix > -1 {
						subSuffix += len(pre)
						return subSuffix, data[:subSuffix], nil
					} else {
						goon = false
					}

				} else {
					goon = false
				}
			}
			return 0, nil, nil

		})
		for es.Scan() {
			text := Str(es.Text())
			strs = strs.Add(Str(text))
		}
		if goon {
			tmpStr = tmpStr[offset:]
		}

	}
	return
}

// func (str Str)MarkByLineContext(n int, filter func(no int,thisline ,pre,next Str) Str){
// 	str.EveryLineContext(n,func(pretext, nextText Str, lineno int, line Str) {

// 	})
// }

func (str Str) ExtractLine(ex func(lineno int, line Str) bool) (out Str, keys Dict[Str]) {
	keys = make(Dict[Str])
	elines := List[Str]{}
	str.EveryLine(func(lineno int, line Str) {

		if !ex(lineno, line) {
			elines = elines.Add(line)
		} else {
			randomKey := str.RandStr(12)
			elines = elines.Add("$${" + randomKey + "}")
			keys[randomKey.Str()] = line
		}
	})
	return elines.Join("\n"), keys
}

func (str Str) Marks(pre string, markedFunc func(text Str, marked bool), suffix ...string) MStrs {

	keys := str.Extract(pre, suffix...)
	ms := str.Mark("")
	keys.With(func(ix int, key Str) Str {
		ms = ms.WithExpand(func(selected MStr) MStrs {
			if selected.Mark {
				return selected.MStrs()
			} else {
				return selected.Str.Mark(key)
			}
		})
		return key
	})
	ms.Every(func(i MStr) {
		markedFunc(i.Str, i.Mark)
	})
	return ms
}

func (str Str) ExtractByRE(pre string, end ...string) (strs Strs) {
	// fmt.Println("quote be")
	raw, mapKeys := str.QuoteMark()
	// fmt.Println("quote af")
	tmpStr := raw
	endPre := pre
	if end != nil {
		endPre = end[0]
	}
	preR := regexp.MustCompile(pre)
	endPreR := regexp.MustCompile(endPre)

	goon := true
	// raw.Color("y").Println("raw")
	last := str
	for goon {
		offset := 0
		buffer := strings.NewReader(tmpStr.String())

		es := bufio.NewScanner(buffer)
		buf := make([]byte, 1)
		es.Buffer(buf, 100*1024*1024)

		// time.Sleep(5 * time.Second)
		es.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {

			if !atEOF {

				if preLoc := preR.FindIndex(data); len(preLoc) > 0 {

					if preLoc[0] == 0 {
						// Str(data).Color("y").Println(Str(data[preLoc[0]:preLoc[1]]))
						if suffixLoc := endPreR.FindIndex(data[1:]); len(suffixLoc) > 0 {
							// Str(data[suffixLoc[0]:suffixLoc[1]]).Color("y", "B").Println("end find")
							if subPreLoc := preR.FindIndex(data[1:]); len(subPreLoc) > 0 && subPreLoc[0] > 0 && subPreLoc[0] < suffixLoc[0] {
								// 最大匹配

								// 先确认能闭合
								preCount := len(preR.FindAll(data[1:], -1))
								endCount := len(endPreR.FindAll(data[1:], -1))
								if endCount < preCount+1 {
									// 闭合符号不够 more data
									return 0, nil, nil
								} else {

									// Str(data[1:]).Color("m", "U").Println(fmt.Sprintf("Hit: %d/%d", preCount, endCount))
									var subSuffixLoc []int
									var subPrefixLoc []int
									subOffset := 0
									t := 0
									for {
										// Str(data[1+subOffset:]).Color("y").Println(t)
										t += 1

										subSuffixLoc = endPreR.FindIndex(data[1+subOffset:])
										subPrefixLoc = preR.FindIndex(data[1+subOffset:])
										if len(subPrefixLoc) == 0 {
											// Str(data[+subOffset:]).Println("no any pre")
											return 0, nil, nil
										}

										// if len(subPrefixLoc) == 0 || len(subSuffixLoc) == 0{
										// 	log.Fatal("err in :",)
										// }
										if subPrefixLoc[0] < subSuffixLoc[0] {
											subOffset += subSuffixLoc[0] + 1
											subSuffixLoc = endPreR.FindIndex(data[subSuffixLoc[0]+1:])
										} else {
											// fmt.Println(subPrefix, subSuffix)
											// Str(data[:subOffset+subSuffix+2]).Color("g").Println("EEE")
											return subOffset + subSuffixLoc[0] + 2, data[:subOffset+subSuffixLoc[0]+2], nil
										}

									}

								}
							}
							suffixLoc[0] = suffixLoc[1]
							offset += suffixLoc[0] + 1

							return suffixLoc[0] + 1, data[0 : suffixLoc[0]+1], nil
						}

						return 0, nil, nil
					} else {
						offset += preLoc[0]
						return preLoc[0], nil, nil
					}
				}

			} else {

				// time.Sleep(2 * time.Second)
				if preLoc := preR.FindIndex(data); len(preLoc) > 0 {
					offset += preLoc[0]
				} else {
					goon = false
				}
			}

			// fmt.Println("EOF ", string(data))
			// time.Sleep(1 * time.Second)

			return 0, nil, nil

		})
		for es.Scan() {
			text := Str(es.Text())
			text = text.Format(mapKeys.MapString())
			// fmt.Println("found:", text)
			// text.Color("g", "B").Println("hit")
			strs = strs.Add(Str(text))
		}
		if goon {
			tmpStr = tmpStr[offset:]
			if tmpStr == last {
				if preLoc := preR.FindIndex([]byte(tmpStr)); len(preLoc) > 0 {
					tmpStr = tmpStr[preLoc[1]:]
				}
				// last.Color("r").Println("last")
				// break
			}
			last = tmpStr
			// Str(tmpStr).Color("g").Println()
		}

	}
	return
}
